package com.my.code.testcode.stream;

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Arrays;
import java.util.IntSummaryStatistics;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 描述:
 * 例子
 *
 * @author 54485
 * @create 2018-09-20 17:35
 */
public class example {

    public static void main(String[] args) {


        /**
         * 例1 用Lambda表达式实现Runnable接口
         */
        //Before Java 8:
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("Before Java8, too much code for too little to do");
            }
        }).start();
        //Java 8 way:
        new Thread(() -> System.out.println("In Java8, Lambda expression rocks !!")).start();


        /**
         * 例2 用Lambda表达式写事件监听程序
         * 要是你用过Swing API，那就少不了事件监听代码，这是使用匿名类的经典例子。现在我们可以用Lambda表达式来抒写更好的事件处理代码。
         */
        // Before Java 8:
        JButton show = new JButton("Show");
        show.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.out.println("Event handling without lambda expression is boring");
            }
        });
        // Java 8 way:
        show.addActionListener((e) -> {
            System.out.println("Light, Camera, Action !! Lambda expressions Rocks");
        });


        /**
         * 例3 用Lambda表达式进行List迭代
         */
        //Prior Java 8 :
        List<String> features = Arrays.asList("Lambdas", "Default Method", "Stream API", "Date and Time API");
        for (String feature : features) {
            System.out.println(feature);
        }
        //In Java 8:
        List features1 = Arrays.asList("Lambdas", "Default Method", "Stream API", "Date and Time API");
        features.forEach(n -> System.out.println(n));


//        /**
//         * 例4 使用Lambda表达式和函数式接口Predicate
//         * 除了提供函数式编程语言级别的支持外，java8同时也新增了一个新的包java.util.function。其中包含了许多类来支持java函数式编程。其中之一是Predicate接口，使用这个接口和lamb表达式就可以以更少的代码为API方法添加更多的动态行为。
//         */
//        public static void main(args[]){
//                List languages = Arrays.asList("Java", "Scala", "C++", "Haskell", "Lisp");
//        System.out.println("Languages which starts with J :");
//        filter(languages, (str)->str.startsWith("J"));
//        System.out.println("Languages which ends with a ");
//        filter(languages, (str)->str.endsWith("a"));
//        System.out.println("Print all languages :");
//        filter(languages, (str)->true);
//        System.out.println("Print no language : ");
//        filter(languages, (str)->false);
//        System.out.println("Print language whose length greater than 4:");
//        filter(languages, (str)->str.length() > 4);
//}
//        public static void filter(List names, Predicate condition) {
//            for(String name: names) {
//                if(condition.test(name)) {
//                    System.out.println(name + " ");
//                }
//            }
//        }


        /**
         * 在这个例子中，我们要将costBeforeTax的每个元素以加上他们的增值税。传递一个Lambda表达式给map方法使之应用于每个元素，之后在用forEach打印结果。
         */
        // Without lambda expressions:
        List<Integer> costBeforeTax = Arrays.asList(100, 200, 300, 400, 500);
        for (Integer cost : costBeforeTax) {
            double price = cost + .12*cost;
            System.out.println(price);
        }
        // With Lambda expression:
//        List costBeforeTax = Arrays.asList(100, 200, 300, 400, 500);
        costBeforeTax.stream().map((cost) -> cost + .12*cost).forEach(System.out::println);


        /**
         * 还有另外一个函数reduce可以将所有值转换为一个值。map跟reduce操作是函数式编程的核心，reduce也被称作折叠操作。reduce并不是一种新的操作，在SQL中我们用的一些聚集函数比如sum，avg，count等他们实际上也是reduce操作，因为他们也是将多个值进行操作然后返回一个值。Stream API定义了reduce函数，可以接受一个Lambda表达式然后组合所有值。Stream类中像IntStream都有内置的方法像average(), count(), sum(), mapToLong(), mapToDouble()等转换方法。我们可以用内置的方法也可以自定义。
         */
        // Old way:
//        List<Integer> costBeforeTax = Arrays.asList(100, 200, 300, 400, 500);
        double total = 0;
        for (Integer cost : costBeforeTax) {
            double price = cost + .12*cost;
            total = total + price;
        }
        System.out.println("Total : " + total);
        // New way:
//        List costBeforeTax = Arrays.asList(100, 200, 300, 400, 500);
        double bill = costBeforeTax.stream().map((cost) -> cost + .12*cost).reduce((sum, cost) -> sum
                + cost).get();
        System.out.println("Total : " + bill);


        /**
         * 用filter创建一个字符串List
         * 在java开发中对大的集合进行过滤是常用的操作。用Lambda表达式和Stream API会让操作变得简单易懂。
         * Stream提供了一个filter()方法，接受一个Predicate对象。这意味着可以传递一个Lambda表达式作为过滤逻辑
         */
        //创建一个长度大于两个字符的字符串List
        List<String> filtered = features.stream().filter(x -> x.length()>
                2).collect(Collectors.toList());
        System.out.printf("Original List : %s, filtered list : %s %n", features, filtered);


        /**
         * 给每个List元素应用函数
         * 在工作中我们经常会碰到这样的情况：给List中每个元素加以一定的操作例如乘以或者除以某个值等。这些操作用map方法再好不过了，我们可以将转换逻辑以Lambda表达式传给map方法来应用于每个元素：
         * //将字符串转为大写然后用逗号连起来
         */
        List<String> G7 = Arrays.asList("USA", "Japan", "France", "Germany", "Italy","U.K.","Canada");
        String G7Countries = G7.stream().map(x -> x.toUpperCase()).collect(Collectors.joining(", "));
        System.out.println(G7Countries);


        /**
         * 复制不同值到子列表
         * 本例演示如何利用Stream类的distinct方法过滤重复值到集合中。
         */
        List<Integer> numbers = Arrays.asList(9, 10, 3, 4, 7, 3, 4);
        List<Integer> distinct = numbers.stream().map( i ->i*i).distinct().collect(Collectors.toList());
        System.out.printf("Original List : %s, Square Without duplicates : %s %n", numbers, distinct);


        /**
         * 计算List中元素的最大，最小，和以及平均值
         * 在Stream类中像IntStream, LongStream and DoubleStream有一个非常有用的方法summaryStattics()，返回IntSummaryStatistics, LongSummaryStatistics or DoubleSummaryStatistics其描述了这个流中元素的统计数据。下面的例子中我们用这个方法来计算一个List中的最大最小值总和以及均值
         */
        List<Integer> primes = Arrays.asList(2, 3, 5, 7, 11, 13, 17, 19, 23, 29);
        IntSummaryStatistics stats = primes.stream().mapToInt((x) -> x).summaryStatistics();
        System.out.println("Highest prime number in List : " + stats.getMax());
        System.out.println("Lowest prime number in List : " + stats.getMin());
        System.out.println("Sum of all prime numbers : " + stats.getSum());
        System.out.println("Average of all prime numbers : " + stats.getAverage());

    }
}
